import json
import logging
import re

from django.contrib.auth import login, logout, authenticate
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View

from apps.users.models import User

from utils.viewmixin import LoginMixin

from apps.users.utils import generate_verify_token, send_verify_mail, check_verify_token

from apps.users.models import Address


class Username(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()

        return JsonResponse({"count": count, "code": "0", "errmsg": "OK"})


class RegisterView(View):
    """
    注册
    前端  ：用户 输入用户名，密码 确认密码 手机号 同意协议，点击注册按钮，发送axios请求
    后端 :
    接受请求 ：接受JSON 数据

    路由:post '/register/'

    业务逻辑： 验证数据 保存到数据库
    响应 JSON格式
    {"code": "0", "errmsg": "OK"}
    {"code": "400", "errmsg": "register fail"}
    """

    def post(self, request):
        # 步骤
        # 1接受请求
        body_byte = request.body
        # 获取json格式数据 转为字典
        body_dict = json.loads(body_byte)

        # 2获取数据
        username = body_dict.get("username")
        password = body_dict.get("password")
        password2 = body_dict.get("password2")
        mobile = body_dict.get("mobile")
        sms_code = body_dict.get("sms_code")
        allow = body_dict.get("allow")

        # 3验证数据
        # 3.1验证是否为空 有没有传
        # all 里传入列表 如果列表里 任一元素为flase或者空 结果就是false
        if not all([username, password, password2, mobile, sms_code, allow]):
            return JsonResponse({"code": "400", "errmsg": "register fail"})
        # 3.2正则验证
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({"code": "400", "errmsg": "register fail"})

        # 4生成用户保存到数据库
        # uesr = User(username=username, password=password, mobile=mobile)
        # user.save();
        user = User.objects.create_user(username=username, password=password, mobile=mobile)
        # 密码加密   数据保存可能不成功捕获异常

        login(request, user)  # 使用django自带的login保持登录

        # 5返回响应（json数据）
        response = JsonResponse({"code": "0", "errmsg": "ok"})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 5)
        return response


class UserMobile(View):
    """
    注册验证手机号是否存在
    前端：发送带手机号的路由
    后端：获取手机号
    接受请求：get请求
    路由：mobiles/<umobile:usermobile>/count/
    业务逻辑：获取手机号进行数据库查询
    响应：{"count": count, "code": "0", "errmsg": "OK"}
    """

    def get(self, request, usermobile):
        count = User.objects.filter(mobile=usermobile).count()

        return JsonResponse({"count": count, "code": "0", "errmsg": "OK"})


class LogoutView(View):
    """
    前端：用户 在首页点击退出 发送axios请求
    后端：
        路由：DELETE请求 ‘http://www.meiduo.site:8080/logout/’
        业务逻辑：清空session和cookie
        响应：Json格式
        {
        "code":"0","errmsg":"OK"
        }
        {
        "code":"400","errmsg":"logout fail"
        }
    """

    def delete(self, request):
        # 使用自带的logout清空保持状态的session
        logout(request)
        # 删除cookie
        try:
            response = JsonResponse({
                "code": "0", "errmsg": "OK"
            })
            response.delete_cookie("username")
            return response
        except Exception:
            logger = logging.getLogger('django')
            logger.info('url:%s method:%s 退出登录失败' % (request.path, request.method))
            return JsonResponse({
                "code": "400", "errmsg": "logout fail"
            })


class UserInfoView(LoginMixin, View):
    def get(self, request):
        return JsonResponse({
            'code': 0,
            'errmsg': '个人中心',
            'info_data': {
                'username': request.user.username,
                'mobile': request.user.mobile,
                'email': request.user.email,
                'email_active': request.user.email_active
            }
        })


class SaveEmailView(View):
    """发邮件"""

    def put(self, request):
        # 1 获取数据 邮箱地址
        json_body = request.body
        data_dict = json.loads(json_body)
        email = data_dict.get("email")
        # 校验数据
        if not email:
            return JsonResponse({"code": "400", "errmsg": "邮箱地址不能为空"})

        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({"code": "400", "errmsg": "邮箱地址格式错误"})
        # 2 保存邮箱地址
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            print(e)
            return JsonResponse({"code": "400", "errmsg": "邮箱保存失败"})

        # 3 发送邮件
        print("发送邮件")
        from django.core.mail import send_mail
        subject = '美多商城邮箱验证'
        recipient_list = [email]
        token = generate_verify_token(request.user.id)
        verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token=%s' % token
        html_message = '<p>美多商城邮箱验证</p>' \
                       '<p>您的邮箱是：%s  点击激活邮箱</p>' \
                       '<p><a href="%s">%s</a></p>' % (email, verify_url, verify_url)
        send_verify_mail(subject=subject, html_message=html_message, recipient_list=recipient_list)

        # 4返回响应
        return JsonResponse({"code": "0", "errmsg": "ok"})


class EmailVerifyView(View):
    """收邮件"""

    def put(self, request):
        # 1获取参数
        token = request.GET.get("token")

        # 2校验参数
        if token is None:
            return JsonResponse({"code": "400", "errmsg": "缺少token"})
        # 3解密获取user_id
        user_id = check_verify_token(token)

        # 4判断user_id是否为空
        if user_id is None:
            return JsonResponse({"code": "400", "errmsg": "token错误"})
        try:
            # 5查询用户 数据
            user = User.objects.get(id=user_id)
        except Exception as e:
            print(e)
            return JsonResponse({"code": "400", "errmsg": "查询不到用户"})

        # 6修改用户邮箱激活字段为True
        user.email_active = True
        user.save()

        # 7返回响应
        return JsonResponse({"code": "0", "errmsg": "ok"})


class LoginView(View):
    def post(self, request):
        # 1 接受数据 json
        body = request.body
        data_dict = json.loads(body)
        username = data_dict.get("username")
        password = data_dict.get("password")
        remembered = data_dict.get("remembered")

        # 2 验证数据 是否为空
        if not all([username, password, str(remembered)]):
            return JsonResponse({"code": "400", "errmsg": "参数不全"})

        # 根据用户传入的username的值 判断是手机号还是用户名
        # 然后设置用户验证是使用手机号还是用户名
        if re.match('1[3-9]\d{9}', username):
            User.USERNAME_FIELD = 'mobile'
        else:
            User.USERNAME_FIELD = 'username'

        # 3 验证用户名和密码是否正确
        # 如果用户名密码正确 返回User对象 否则返回None
        user = authenticate(username=username, password=password)

        if user is None:
            return JsonResponse({"code": "400", "errmsg": "用户名或者密码错误"})

        # 4 状态保持  session
        login(request, user)

        # 5 判断是否记住登录 设置session的有效期
        if remembered:
            # 记住登录 默认2周
            request.session.set_expiry(None)

        else:
            # 不记住登录  浏览器关闭 session过期
            request.session.set_expiry(0)

        response = JsonResponse({"code": "0", "errmsg": "ok"})
        # 把用户名保存到cookie 方便在首页显示 有效期产品决定
        response.set_cookie('username', user.username, max_age=3600 * 24 * 5)

        # 6 返回响应
        return response


"""
需求  增加一个收货地址
前端    用户填写完收货地址 点击保存  发送一个axios请求    把数据传过来

后端

    请求  接受请求 获取和验证参数
    逻辑  把数据保存到数据库
    返回响应

    路由  POST  /addresses/create/

    {'code':0,"errmsg":"ok","address":{"title":"老家地址","mobile":"1551234431",,,,}}

"""


class AddressCreateView(LoginMixin, View):

    def post(self, request):
        # 1接收请求
        body = request.body
        data_dict = json.loads(body)

        # 2获取参数
        receiver = data_dict.get("receiver")
        province_id = data_dict.get("province_id")
        city_id = data_dict.get("city_id")
        district_id = data_dict.get("district_id")
        place = data_dict.get("place")
        mobile = data_dict.get("mobile")
        tel = data_dict.get("tel")
        email = data_dict.get("email")

        # 3验证参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({"code": "400", "errmsg": "参数不全"})
        # 正则验证
        # if re.match()
        #
        # if tel: 固定电话和邮箱 需要判断存在后 再做正则验证
        #     if re.match()

        # 4保存数据到数据库
        # 创建一个Address对象address
        # address = Address(xxx=xxx)
        # address.save()

        user = request.user
        try:
            address = Address.objects.create(
                user=user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
        except Exception as e:
            print(e)
            return JsonResponse({"code": "400", "errmsg": "保存数据失败"})

        # 数据转为字典
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 5返回响应
        return JsonResponse({'code': 0, "errmsg": "ok", "address": address_dict})


"""
获取所有收货地址返回
路由   get   /addresses/

返回
{'code': 0, "errmsg": "ok", "addresses": []}
"""


class AddressView(LoginMixin, View):
    def get(self, request):
        # 1获取用户对象
        user = request.user
        # 2查询当前用户 的所有地址信息
        # user.addresses 这样方式会拿到所有数据 包括逻辑删除的
        addresses = Address.objects.filter(user=user, is_deleted=False)  # is_deleted=False过滤查询没有删除的

        # 3转为字典数据
        addresses_list = []
        for address in addresses:
            addresses_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })

        # 4 返回
        return JsonResponse({'code': 0, "errmsg": "ok", "addresses": addresses_list})

    def put(self, request, id):
        """
        修改收货地址
        :param request:
        :param id: 收货地址id
        :return: success-{'code': 0, "errmsg": "ok", "addresses": {'id':...,...}}  fail-{'code': 404, "errmsg": "xxx"}
        """
        user = request.user
        if user is None:
            return JsonResponse({'code': 400, "errmsg": "用户未登录"})
        body = request.body
        dict_info = json.loads(body)
        if not all([dict_info.get('receiver'), dict_info.get('province_id'), dict_info.get('city_id'),
                    dict_info.get('district_id'), dict_info.get('place'), dict_info.get('mobile')]):
            return JsonResponse({"code": "400", "errmsg": "参数不全"})
        try:
            addr_obj = Address.objects.get(id=id)
            addr_obj.city_id = dict_info.get('city_id')
            addr_obj.district_id = dict_info.get('district_id')
            addr_obj.email = dict_info.get('email')
            addr_obj.mobile = dict_info.get('mobile')
            addr_obj.place = dict_info.get('place')
            addr_obj.province_id = dict_info.get('province_id')
            addr_obj.receiver = dict_info.get('receiver')
            addr_obj.tel = dict_info.get('tel')
            addr_obj.title = dict_info.get('title')
            addr_obj.save()
        except Exception:
            return JsonResponse({'code': 400, "errmsg": "保存错误"})
        address_dict = {
            "id": addr_obj.id,
            "title": addr_obj.title,
            "receiver": addr_obj.receiver,
            "province": addr_obj.province.name,
            "city": addr_obj.city.name,
            "district": addr_obj.district.name,
            "place": addr_obj.place,
            "mobile": addr_obj.mobile,
            "tel": addr_obj.tel,
            "email": addr_obj.email
        }

        return JsonResponse({'code': 0, "errmsg": "ok", "address": address_dict})

    def delete(self, request, id):
        """
        删除收货地址
        :param request:
        :param id: 收货地址id
        :return: {'code': 0, "errmsg": "ok"}
        """
        user = request.user
        if user is None:
            return JsonResponse({'code': 400, "errmsg": "用户未登录"})
        try:
            addr_obj = Address.objects.get(id=id)
            addr_obj.is_deleted = True
            addr_obj.save()
        except Exception:
            return JsonResponse({'code': 400, "errmsg": "数据库删除错误"})

        return JsonResponse({'code': 0, "errmsg": "ok"})


class PasswordView(View):
    def put(self, request):
        """实现修改密码逻辑"""
        # 接收参数
        dict = json.loads(request.body.decode())
        old_password = dict.get('old_password')
        new_password = dict.get('new_password')
        new_password2 = dict.get('new_password2')

        # 校验参数
        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400,
                                 'errmsg': '缺少必传参数'})
        result = request.user.check_password(old_password)
        if not result:
            return JsonResponse({'code': 400,
                                 'errmsg': '原始密码不正确'})
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400,
                                 'errmsg': '密码最少8位,最长20位'})
        if new_password != new_password2:
            return JsonResponse({'code': 400,
                                 'errmsg': '两次输入密码不一致'})
        # 修改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'errmsg': '修改密码失败'})

        # 清理状态保持信息
        logout(request)
        response = JsonResponse({'code': 0,
                                 'errmsg': 'ok'})
        response.delete_cookie('username')

        # # 响应密码修改结果：重定向到登录界面
        return response
